package ee.nlp.evn.tools;

import ee.nlp.evn.entities.*;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class T3olpAjavDocumentLoader {

	public static Text parseFromFile(File t3olpTmxFile, String encoding)
			throws IOException {
		// ---------------------------------------------------------------------------------------
		// Faili sisselaadimine
		// ---------------------------------------------------------------------------------------
		StringBuilder fromFile = new StringBuilder();
		try {
			FileInputStream fstream = new FileInputStream(t3olpTmxFile);
			DataInputStream in = new DataInputStream(fstream);
			BufferedReader sisend = new BufferedReader(new InputStreamReader(
					in, encoding));
			String rida = null;
			while ((rida = sisend.readLine()) != null) {
				if (rida.length() > 0) {
					fromFile.append(rida + "\n");
				}
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			System.exit(-1);
		} catch (IOException e) {
			e.printStackTrace();
			System.exit(-1);
		}
		// ---------------------------------------------------------------------------------------
		// Tekstilise osa kogumine ...
		// ---------------------------------------------------------------------------------------
		BufferedReader input = new BufferedReader(new StringReader(
				fromFile.toString()));
		String line = null;
		StringBuilder ignorePart = null;
		StringBuilder docContent = new StringBuilder();
		Stack<PositionAnnotation> currentAnnotations = new Stack<PositionAnnotation>();
		ArrayList<PositionAnnotation> collectedAnnotations = new ArrayList<PositionAnnotation>();
		Pattern startTag = Pattern.compile("<([^>\\/]+)>");
		Pattern endTag = Pattern.compile("</([^>]+)>");
		Pattern fullTag = Pattern.compile("<([^>]+)/\\s*>");
		while ((line = input.readLine()) != null) {
			// ---------------------------------------------------------------------------------------
			// Ignoreeritav osa
			// ---------------------------------------------------------------------------------------
			if (line.length() > 0 && line.equals("<ignoreeri>")) {
				ignorePart = new StringBuilder();
				while ((line = input.readLine()) != null) {
					if (line.length() > 0 && line.equals("</ignoreeri>")) {
						break;
					}
					ignorePart.append(line);
				}
				continue;
			}
			// ---------------------------------------------------------------------------------------
			// Sisuline osa
			// ---------------------------------------------------------------------------------------
			if (line.length() > 0) {
				Matcher startTagM = startTag.matcher(line);
				Matcher endTagM = endTag.matcher(line);
				Matcher fullTagM = fullTag.matcher(line);
				if (startTagM.matches()) {
					String content = startTagM.group(1);
					PositionAnnotation a = null;
					if (content.startsWith("TIMEX")) {
						a = new PositionAnnotation("TIMEX");
						a.setFeatures(eraldaXMLtagiAtribuudid(content));
					} else {
						a = new PositionAnnotation(content);
					}
					long startPos = (long) docContent.length();
					if (startPos > 0) {
						startPos++;
					}
					a.setStart(startPos);
					currentAnnotations.push(a);
				} else if (endTagM.matches()) {
					// String content = endTagM.group(1);
					PositionAnnotation a = currentAnnotations.pop();
					a.setEnd((long) docContent.length());
					addMetaPropertiesToPositionAnnotation(a, docContent);
					collectedAnnotations.add(a);
				} else if (fullTagM.matches()) {
					String content = fullTagM.group(1);
					PositionAnnotation a = null;
					if (content.startsWith("TIMEX")) {
						a = new PositionAnnotation("TIMEX");
						a.setFeatures(eraldaXMLtagiAtribuudid(content));
					} else {
						a = new PositionAnnotation(content);
					}
					a.setStart((long) docContent.length());
					a.setEnd((long) docContent.length());
					collectedAnnotations.add(a);
				} else {
					String[] parts = line.split("\\s{4}");
					if (parts.length < 2) {
						throw new IOException(" Unexpected t3-olp format: '"
								+ line + "'");
					} else {
						String word = parts[0];
						if (docContent.length() > 0) {
							docContent.append(" ");
						}
						docContent.append(word);
						for (int i = 1; i < parts.length; i++) {
							HashMap<String, String> fp = eraldaReastElemendid(parts[i]);
							PositionAnnotation a = new PositionAnnotation(
									"MorphWord");
							// meta-properties
							fp.put("string", word);
							fp.put("length", String.valueOf(word.length()));
							a.setFeatures(fp);
							a.setStart(docContent.length() - word.length());
							a.setEnd(docContent.length());
							collectedAnnotations.add(a);
						}
					}
				}
			}
		}

		// Teisendame andmed

		Text newDocument = new Text();
		Sentence lause = new Sentence();
		PositionAnnotation prev_pa = null;

		for (PositionAnnotation ta : collectedAnnotations) {
			System.out.print(ta.toString() + "\n");
			if (ta.getContent().equals("MorphWord")) {
				Word w = null;
				int variant = 0;
				if (prev_pa != null
						&& ta.getContent().equals(prev_pa.getContent())
						&& ta.getStart() == prev_pa.getStart()
						&& ta.getEnd() == prev_pa.getEnd()) {
					w = lause.getWords().get(lause.getWords().size() - 1);
					variant = w.getAllTags().size();
				} else {
					w = new Word(ta.getFeatures().get("string"));
				}
				w.addTag("trunk", ta.getFeatures().get("lemma") + "+"
						+ ta.getFeatures().get("ending"), variant);
				w.addTag("POS",
						ta.getFeatures().get("POS").replaceAll("_", ""),
						variant);
				String fms[] = ta.getFeatures().get("form").split(" ");
				for (int i = 0; i < fms.length; i++) {
					if (!fms[i].isEmpty()) {
						w.addTag("morph", fms[i], variant);
					}
				}
				if (variant == 0) {
					lause.addWord(w);
				}
			} else if (ta.getContent().equals("kindel_piir")) {
				lause.addOLP("P");
			} else if (ta.getContent().equals("kiil")) {
				lause.addOLP("KL");
				String cnt[] = ta.getFeatures().get("string").split(" ");
				ArrayList<Word> ws = (ArrayList<Word>) lause.getWords();
				int l = ws.size() - 1;
				int cl = cnt.length;
				int a = l;
				if (cl > 1) {
					for (a = l; a >= 0; a--) {
						if (ws.get(a).getUsedForm().equals(cnt[cl - 1])) {
							cl--;
							if (cl == 0)
								break;
						}
					}
				}
				Word ka = new Word("");
				ka.addTag("OLP", "KA");
				ws.add(a, ka);
			} else if (ta.getContent().equals("s")) {
				newDocument.addSentence(lause);
				lause = new Sentence();
			} else {
				System.err.print("NB! Tundmatu: " + ta.toString() + "\n");
			}
			prev_pa = ta;
		}
		return newDocument;
	}

	/**
	 * Eraldame analyysireast elemendid: lemma, lopp, sonaliik, vorminimetus;
	 * 
	 * @param analyysiRida
	 */
	private static HashMap<String, String> eraldaReastElemendid(
			String analyysiRida) {
		HashMap<String, String> fp = new HashMap<String, String>();
		/******* <Sona tyvi> ja <Sona lopp> ************/
		int esimeneKaldkriips = leiaEsimeseKaldkriipsuIndex(analyysiRida);
		// kui leidub sonalopu tahis
		if (analyysiRida.lastIndexOf("+") > -1) {
			// lemma on algusest kuni sonalopu tahiseni
			fp.put("lemma",
					analyysiRida.substring(0, analyysiRida.lastIndexOf("+")));
			fp.put("ending", analyysiRida.substring(
					analyysiRida.lastIndexOf("+") + 1, esimeneKaldkriips - 1));
		} else {
			// lemma on algusest kuni tyhikuni enne esimest alamsonet "//"
			fp.put("lemma", analyysiRida.substring(0, esimeneKaldkriips - 1));
			fp.put("ending", "0");
		}
		int viimaneAlaJoon = analyysiRida.lastIndexOf("_");
		int viimaneKaldkriips = analyysiRida.lastIndexOf("/");
		/*********** <Sonaliik> ***************/
		fp.put("POS",
				analyysiRida.substring(viimaneAlaJoon - 2, viimaneAlaJoon + 1));
		/********* <vormiNimetused> ***********/
		if ((viimaneKaldkriips - 2) - (viimaneAlaJoon + 2) > 0) {
			String form = analyysiRida.substring(viimaneAlaJoon + 2,
					viimaneKaldkriips - 2);
			form = form.replaceAll(",$", "");
			fp.put("form", form);
		} else {
			fp.put("form", "");
		}
		return fp;
	}

	/**
	 * Morf analysaatori analyysirida on kujul: <blockquote> tüvi+lõpp //
	 * [sõnaliik] [vormi nimetus] // </blockquote> Leiame analyysireas vasakult
	 * esimese l6iku "[sõnaliik] [vormi nimetus]" ymbritseva symboli '/'
	 * indeksi.
	 * 
	 * @param analyysiRida
	 * @return
	 */
	private static int leiaEsimeseKaldkriipsuIndex(String analyysiRida) {
		int i = analyysiRida.length() - 1;
		int symboleidSeni = 0;
		for (; i > -1; i--) {
			if (analyysiRida.charAt(i) == '/') {
				symboleidSeni++;
			}
			if (symboleidSeni == 4) {
				break;
			}
		}
		return i;
	}

	/**
	 * Eraldame XML-tag'i atribuudid Map elementidena;
	 */
	private static HashMap<String, String> eraldaXMLtagiAtribuudid(
			String tagHead) {
		HashMap<String, String> fp = new HashMap<String, String>();
		Pattern attrPat = Pattern.compile("(\\S+)=\"([^\"]+)\"");
		Matcher matcher = attrPat.matcher(tagHead);
		while (matcher.find()) {
			String aName = matcher.group(1);
			String aValue = matcher.group(2);
			fp.put(aName, aValue);
		}
		return fp;
	}

	/**
	 * Lisab annotatsiooni featureMap'i vaikimisi eeldatavad metaatribuudid
	 * (string, length);
	 */
	private static void addMetaPropertiesToPositionAnnotation(
			PositionAnnotation a, StringBuilder docContent) {
		String str = docContent.substring((int) a.getStart(), (int) a.getEnd());
		if (a.getFeatures() == null) {
			a.setFeatures(new HashMap<String, String>());
		}
		(a.getFeatures()).put("string", str);
		(a.getFeatures()).put("length", String.valueOf(str.length()));
	}

}
